package com.baoyouqun.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.cola.dto.SingleResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baoyouqun.base.utils.ExcelTool;
import com.baoyouqun.domain.Enum.ResourceTypeEnum;
import com.baoyouqun.domain.Query.LeopardFriendPageQuery;
import com.baoyouqun.domain.VO.CellphoneDuplicateVO;
import com.baoyouqun.domain.VO.LeopardFriendDetailVO;
import com.baoyouqun.entity.User;
import com.baoyouqun.entity.UserResource;
import com.baoyouqun.entity.UserVipTime;
import com.baoyouqun.entity.VipLevel;
import com.baoyouqun.mapper.*;
import com.baoyouqun.service.LeopardFriendManageService;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 豹友管理独立Service实现（全程批量查询，无循环查库）
 */
@Service
public class LeopardFriendManageServiceImpl implements LeopardFriendManageService {

    // 常量定义
    private static final DateTimeFormatter DT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final String EXPORT_FILE_PREFIX = "豹友详情列表_";

    // 依赖注入（仅注入必要Mapper，职责单一）
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserResourceMapper userResourceMapper;
    @Resource
    private UserVipTimeMapper userVipTimeMapper;
    @Resource
    private VipLevelMapper vipLevelMapper;
    @Resource
    private DemandMapper demandMapper; // 假设存在帖子表Mapper（统计帖子数）
//    @Resource
//    private FriendMapper friendMapper; // 假设存在好友表Mapper（统计好友数）


    // ======================== 1. 分页查询（批量查所有关联数据）========================
    @Override
    public SingleResponse<IPage<LeopardFriendDetailVO>> pageLeopardFriend(LeopardFriendPageQuery query) {
        // 1. 构建分页对象+查询条件（基础用户筛选）
        IPage<User> userPage = new Page<>(query.getCurrent(), query.getSize());
        LambdaQueryWrapper<User> userWrapper = buildUserQueryWrapper(query);

        // 2. 批量查询用户基础数据（1次DB查询）
        userPage = userMapper.selectPage(userPage, userWrapper);
        List<User> userList = userPage.getRecords();
        if (CollUtil.isEmpty(userList)) {
            return SingleResponse.of(new Page<>(query.getCurrent(), query.getSize(), 0));
        }

        // 3. 提取所有用户ID（用于后续批量关联查询）
        List<String> userIds = userList.stream().map(User::getId).collect(Collectors.toList());

        // 4. 批量查询关联数据（4次DB查询，无循环）
        Map<String, Map<ResourceTypeEnum, List<String>>> resourceMap = batchGetUserResource(userIds); // 资源（拥有/需要）
        Map<String, UserVipTime> validVipMap = batchGetValidVip(userIds); // 有效VIP
        Map<String, VipLevel> vipLevelMap = batchGetVipLevel(validVipMap.values().stream()
                .map(UserVipTime::getVipLevelId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList())); // 会员等级
        Map<String, Integer> postCountMap = batchGetPostCount(userIds); // 帖子数
        Map<String, Integer> friendCountMap = new HashMap<>();
//                batchGetFriendCount(userIds); // 好友数

        // 5. 转换为VO（内存循环，无DB操作）
        List<LeopardFriendDetailVO> voList = userList.stream().map(user -> convertToDetailVO(
                user, resourceMap, validVipMap, vipLevelMap, postCountMap, friendCountMap
        )).collect(Collectors.toList());

        // 6. 构建分页VO返回
        IPage<LeopardFriendDetailVO> voPage = new Page<>(
                userPage.getCurrent(), userPage.getSize(), userPage.getTotal()
        );
        voPage.setRecords(voList);
        return SingleResponse.of(voPage);
    }


    // ======================== 2. 导出（复用批量查询逻辑，无额外DB操作）========================
    @Override
    public void exportLeopardFriend(LeopardFriendPageQuery query, HttpServletResponse response) throws IOException {
        // 1. 构建查询条件（同分页，查全量数据）
        LambdaQueryWrapper<User> userWrapper = buildUserQueryWrapper(query);
        List<User> userList = userMapper.selectList(userWrapper);

        // 2. 无数据时导出空Excel
        if (CollUtil.isEmpty(userList)) {
            exportEmptyExcel(response, EXPORT_FILE_PREFIX);
            return;
        }

        // 3. 批量查询关联数据（同分页逻辑，4次DB查询）
        List<String> userIds = userList.stream().map(User::getId).collect(Collectors.toList());
        Map<String, Map<ResourceTypeEnum, List<String>>> resourceMap = batchGetUserResource(userIds);
        Map<String, UserVipTime> validVipMap = batchGetValidVip(userIds);
        Map<String, VipLevel> vipLevelMap = batchGetVipLevel(validVipMap.values().stream()
                .map(UserVipTime::getVipLevelId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList()));
        Map<String, Integer> postCountMap = batchGetPostCount(userIds);
        Map<String, Integer> friendCountMap = new HashMap<>();
//        batchGetFriendCount(userIds);


        // 4. 转换为导出VO列表
        List<LeopardFriendDetailVO> exportList = userList.stream().map(user -> convertToDetailVO(
                user, resourceMap, validVipMap, vipLevelMap, postCountMap, friendCountMap
        )).collect(Collectors.toList());

        // 5. 生成Excel并响应
        generateExcel(exportList, response);
    }


    // ======================== 3. 检查手机号重复（批量查重复用户，无循环）========================
    @Override
    public SingleResponse<CellphoneDuplicateVO> checkCellphoneDuplicate(String cellphone) {
        CellphoneDuplicateVO resultVO = new CellphoneDuplicateVO();
        if (StrUtil.isBlank(cellphone)) {
            resultVO.setIsDuplicate(false);
            resultVO.setDuplicateList(new ArrayList<>());
            return SingleResponse.of(resultVO);
        }

        // 1. 批量查询重复用户（1次DB查询，排除注销/非公开用户）
        List<User> duplicateUsers = userMapper.selectList(new LambdaQueryWrapper<User>()
                .eq(User::getCellphone, cellphone)
                .eq(User::getLogout, false)
                .eq(User::getIsPublic, true));

        // 2. 转换为VO（内存操作）
        if (CollUtil.isNotEmpty(duplicateUsers)) {
            resultVO.setIsDuplicate(true);
            // 批量查重复用户的资源（1次DB查询）
            List<String> dupUserIds = duplicateUsers.stream().map(User::getId).collect(Collectors.toList());
            Map<String, Map<ResourceTypeEnum, List<String>>> dupResourceMap = batchGetUserResource(dupUserIds);

            List<LeopardFriendDetailVO> dupVOList = duplicateUsers.stream().map(user -> {
                LeopardFriendDetailVO vo = new LeopardFriendDetailVO();
                vo.setUserId(user.getId());
                vo.setName(StrUtil.isNotBlank(user.getName()) ? user.getName() : "未填写");
                vo.setCellphone(user.getCellphone());
                vo.setCompany(StrUtil.isNotBlank(user.getCompany()) ? user.getCompany() : "未填写");
                vo.setJob(StrUtil.isNotBlank(user.getJob()) ? user.getJob() : "未填写");
                vo.setRegion(StrUtil.join("", user.getProvince(), user.getCity(), user.getDistrict()));
                // 填充资源
                Map<ResourceTypeEnum, List<String>> res = dupResourceMap.getOrDefault(user.getId(), new HashMap<>());
                vo.setOwnResource(CollUtil.isNotEmpty(res.get(ResourceTypeEnum.OWN)) ?
                        String.join(",", res.get(ResourceTypeEnum.OWN)) : "无");
                vo.setNeedResource(CollUtil.isNotEmpty(res.get(ResourceTypeEnum.NEED)) ?
                        String.join(",", res.get(ResourceTypeEnum.NEED)) : "无");
                return vo;
            }).collect(Collectors.toList());
            resultVO.setDuplicateList(dupVOList);
        } else {
            resultVO.setIsDuplicate(false);
            resultVO.setDuplicateList(new ArrayList<>());
        }
        return SingleResponse.of(resultVO);
    }


    // ======================== 私有工具方法（批量查询+VO转换）========================

    /**
     * 构建用户查询条件（分页/导出通用）
     */
    private LambdaQueryWrapper<User> buildUserQueryWrapper(LeopardFriendPageQuery query) {
        return new LambdaQueryWrapper<User>()
                .like(StrUtil.isNotBlank(query.getName()), User::getName, query.getName())
                .like(StrUtil.isNotBlank(query.getCellphone()), User::getCellphone, query.getCellphone())
                .like(StrUtil.isNotBlank(query.getCompany()), User::getCompany, query.getCompany())
                .like(StrUtil.isNotBlank(query.getJob()), User::getJob, query.getJob())
                .like(StrUtil.isNotBlank(query.getEducation()), User::getEducation, query.getEducation())
                .eq(StrUtil.isNotBlank(query.getIndustry()), User::getIndustry, query.getIndustry())
                .eq(StrUtil.isNotBlank(query.getProvince()), User::getProvince, query.getProvince())
                .eq(StrUtil.isNotBlank(query.getCity()), User::getCity, query.getCity())
                .eq(StrUtil.isNotBlank(query.getDistrict()), User::getDistrict, query.getDistrict())
                .eq(query.getDisEnable() != null, User::getDisEnable, query.getDisEnable())
                // 豹子号匹配（MP支持apply+<script>，但此处逻辑简单，直接拼接）
                .apply(query.getIsLuckyNumber() != null,
                        Boolean.TRUE.equals(query.getIsLuckyNumber()) ?
                                "RIGHT(cellphone, 3) = CONCAT(SUBSTR(cellphone, LENGTH(cellphone)-1, 1), SUBSTR(cellphone, LENGTH(cellphone)-1, 1), SUBSTR(cellphone, LENGTH(cellphone)-1, 1))" :
                                "RIGHT(cellphone, 3) != CONCAT(SUBSTR(cellphone, LENGTH(cellphone)-1, 1), SUBSTR(cellphone, LENGTH(cellphone)-1, 1), SUBSTR(cellphone, LENGTH(cellphone)-1, 1))");
    }

    /**
     * 批量查询用户资源（拥有/需要）
     *
     * @param userIds 用户ID列表
     * @return key=userId, value={key=资源类型, value=资源名称列表}
     */
    private Map<String, Map<ResourceTypeEnum, List<String>>> batchGetUserResource(List<String> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return new HashMap<>();
        }
        // 1次DB查询：查所有用户的OWN+NEED资源
        List<UserResource> resourceList = userResourceMapper.selectBatchByUserIdsAndTypes(userIds);
        // 分组：userId → 资源类型 → 资源名称
        return resourceList.stream().collect(Collectors.groupingBy(
                UserResource::getUserId,
                Collectors.groupingBy(
                        UserResource::getResourceTypeEnum,
                        Collectors.mapping(UserResource::getName, Collectors.toList())
                )
        ));
    }

    /**
     * 批量查询用户有效VIP（endTime > 当前时间）
     */
    private Map<String, UserVipTime> batchGetValidVip(List<String> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return new HashMap<>();
        }
        // 1次DB查询：查所有用户的有效VIP
        List<UserVipTime> vipList = userVipTimeMapper.selectBatchValidByUserIds(userIds);
        // 分组：userId → UserVipTime（多个时取最新的）
        return vipList.stream().collect(Collectors.toMap(
                UserVipTime::getUserId,
                vip -> vip,
                (oldVal, newVal) -> newVal.getEndTime().isAfter(oldVal.getEndTime()) ? newVal : oldVal
        ));
    }

    /**
     * 批量查询会员等级
     */
    private Map<String, VipLevel> batchGetVipLevel(List<String> vipLevelIds) {
        if (CollUtil.isEmpty(vipLevelIds)) {
            return new HashMap<>();
        }
        // 1次DB查询：查所有会员等级
        List<VipLevel> vipLevelList = vipLevelMapper.selectBatchByLevelIds(vipLevelIds);
        // 分组：vipLevelId → VipLevel
        return vipLevelList.stream().collect(Collectors.toMap(
                VipLevel::getId,
                level -> level,
                (a, b) -> b
        ));
    }

    /**
     * 批量查询用户帖子数
     */
    private Map<String, Integer> batchGetPostCount(List<String> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return new HashMap<>();
        }
        // 1次DB查询：统计每个用户的有效帖子数
        List<Map<String, Object>> postCountList = demandMapper.selectBatchPostCount(userIds);
        // 分组：userId → 帖子数
        return postCountList.stream().collect(Collectors.toMap(
                map -> map.get("user_id").toString(),
                map -> Integer.parseInt(map.get("post_count").toString()),
                (a, b) -> b
        ));
    }

    /**
     * 批量查询用户好友数
     */
/*
    private Map<String, Integer> batchGetFriendCount(List<String> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return new HashMap<>();
        }
        // 1次DB查询：统计每个用户的好友数
        List<Map<String, Object>> friendCountList = friendMapper.selectBatchFriendCount(userIds);
        // 分组：userId → 好友数
        return friendCountList.stream().collect(Collectors.toMap(
                map -> map.get("user_id").toString(),
                map -> Integer.parseInt(map.get("friend_count").toString()),
                (a, b) -> b
        ));
    }
*/

    /**
     * 转换User为LeopardFriendDetailVO（纯内存操作）
     */
    private LeopardFriendDetailVO convertToDetailVO(
            User user,
            Map<String, Map<ResourceTypeEnum, List<String>>> resourceMap,
            Map<String, UserVipTime> validVipMap,
            Map<String, VipLevel> vipLevelMap,
            Map<String, Integer> postCountMap,
            Map<String, Integer> friendCountMap
    ) {
        LeopardFriendDetailVO vo = new LeopardFriendDetailVO();
        // 1. 基础信息
        vo.setUserId(user.getId());
        vo.setName(StrUtil.isNotBlank(user.getName()) ? user.getName() : "未填写");
        vo.setSex(StrUtil.isNotBlank(user.getSex()) ? user.getSex() : "未知");
        vo.setCellphone(StrUtil.isNotBlank(user.getCellphone()) ? user.getCellphone() : "未填写");
        vo.setIndustry(StrUtil.isNotBlank(user.getIndustry()) ? user.getIndustry() : "未填写");
        vo.setCompany(StrUtil.isNotBlank(user.getCompany()) ? user.getCompany() : "未填写");
        vo.setJob(StrUtil.isNotBlank(user.getJob()) ? user.getJob() : "未填写");
        vo.setEducation(StrUtil.isNotBlank(user.getEducation()) ? user.getEducation() : "未填写");
        // 拼接地区（去空）
        String region = StrUtil.join("",
                StrUtil.nullToEmpty(user.getProvince()),
                StrUtil.nullToEmpty(user.getCity()),
                StrUtil.nullToEmpty(user.getDistrict())
        );
        vo.setRegion(StrUtil.isNotBlank(region) ? region : "未填写");
        vo.setLastLoginTime(user.getLastLoginTime());
        vo.setDisEnable(Objects.nonNull(user.getDisEnable()) ? user.getDisEnable() : false);
        vo.setLogout(Objects.nonNull(user.getLogout()) ? user.getLogout() : false);

        // 2. 资源信息（从resourceMap取）
        Map<ResourceTypeEnum, List<String>> res = resourceMap.getOrDefault(user.getId(), new HashMap<>());
        vo.setOwnResource(CollUtil.isNotEmpty(res.get(ResourceTypeEnum.OWN)) ?
                String.join(",", res.get(ResourceTypeEnum.OWN)) : "无");
        vo.setNeedResource(CollUtil.isNotEmpty(res.get(ResourceTypeEnum.NEED)) ?
                String.join(",", res.get(ResourceTypeEnum.NEED)) : "无");

        // 3. 统计信息（从countMap取）
        vo.setPostCount(postCountMap.getOrDefault(user.getId(), 0));
        vo.setFriendCount(friendCountMap.getOrDefault(user.getId(), 0));

        // 4. VIP信息（从vipMap取）
        UserVipTime vipTime = validVipMap.get(user.getId());
        if (Objects.nonNull(vipTime) && vipTime.getEndTime().isAfter(LocalDateTime.now())) {
            // 计算剩余天数（向上取整）
            long remainDays = ChronoUnit.DAYS.between(LocalDateTime.now(), vipTime.getEndTime());
            vo.setRemainAccessDays((int) (remainDays <= 0 ? 1 : remainDays));
            // 会员等级名称
            VipLevel vipLevel = vipLevelMap.get(vipTime.getVipLevelId());
            vo.setVipLevelName(Objects.nonNull(vipLevel) ? vipLevel.getLevelName() : "临时会员");
        } else {
            vo.setRemainAccessDays(0);
            vo.setVipLevelName("临时会员");
        }
        return vo;
    }

    /**
     * 生成Excel并响应（Hutool实现）
     */
    private void generateExcel(List<LeopardFriendDetailVO> dataList, HttpServletResponse response) throws IOException {
        // 1. 初始化ExcelWriter
        ExcelWriter writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);

        // 2. 表头映射（与VO字段一一对应）
        writer.addHeaderAlias("name", "姓名");
        writer.addHeaderAlias("sex", "性别");
        writer.addHeaderAlias("cellphone", "手机号");
        writer.addHeaderAlias("industry", "所在行业");
        writer.addHeaderAlias("company", "所在公司");
        writer.addHeaderAlias("job", "职位信息");
        writer.addHeaderAlias("education", "教育程度");
        writer.addHeaderAlias("region", "所在区域");
        writer.addHeaderAlias("ownResource", "拥有资源");
        writer.addHeaderAlias("needResource", "需要资源");
        writer.addHeaderAlias("postCount", "帖子数");
        writer.addHeaderAlias("friendCount", "好友数");
        writer.addHeaderAlias("remainAccessDays", "访问剩余时长（天）");
        writer.addHeaderAlias("vipLevelName", "会员等级");
        writer.addHeaderAlias("lastLoginTimeDesc", "最后登录时间");
        writer.addHeaderAlias("status", "状态");

        // 3. 写入数据（带表头）
        writer.write(dataList, true);

        // 4. 设置响应头（解决中文乱码+下载弹窗）
        setExportResponseHeader(response, EXPORT_FILE_PREFIX + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));

        // 5. 输出流（自动关闭）
        try (ServletOutputStream out = response.getOutputStream()) {
            writer.flush(out, true);
        } finally {
            writer.close(); // 释放POI资源
        }
    }

    /**
     * 导出空Excel（无数据时调用）
     */
    private void exportEmptyExcel(HttpServletResponse response, String fileNamePrefix) throws IOException {
        ExcelWriter writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);
        setExportResponseHeader(response, fileNamePrefix + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        try (ServletOutputStream out = response.getOutputStream()) {
            writer.flush(out, true);
        } finally {
            writer.close();
        }
    }

    /**
     * 设置导出响应头（通用方法）
     */
    private void setExportResponseHeader(HttpServletResponse response, String fileName) throws IOException {
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        ExcelTool.setExportFileName(response, "豹友详情列表");

    }
}